package com.zhiwen.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @Auther: wuzhiwen
 * @Date: 2018/12/26 17:22
 * @Description: NIO实现
 */
public class NIOServer {

    //标记位
    private int flag = 0;
    //定义缓冲区大小
    private int blockSize = 4096;
    //发送缓冲区
    private ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);
    //接收缓冲区
    private ByteBuffer receiveBuffer = ByteBuffer.allocate(blockSize);

    private Selector selector;

    public NIOServer(int port) throws IOException {
        //服务端管道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //是否阻塞 不阻塞
        serverSocketChannel.configureBlocking(false);
        //创建服务端socket
        ServerSocket socket = serverSocketChannel.socket();
        //绑定端口
        socket.bind(new InetSocketAddress(port));
        //打开选择器
        selector = Selector.open();
        //将管道注册到选择器
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //答应下端口
        System.out.println("port start:" + port);
    }

    /**
     * 监听端口
     */
    public void listen() throws IOException, InterruptedException {
        while (true) {
            Thread.sleep(1000);
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                iterator.remove();
                //业务逻辑
                handleKey(selectionKey);


            }
        }
    }

    public void handleKey(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel server = null;
        SocketChannel client = null;
        String sendMessage;
        String resiveMessage;
        int count = 0;
        //判断是否可以接受
        if (selectionKey.isAcceptable()) {
            //通过selectKey获取服务端管道
            server = (ServerSocketChannel) selectionKey.channel();
            //根据服务端管道获取客户端管道
            client = server.accept();
            //设定不阻塞
            client.configureBlocking(false);

            //注册读数据
            selectionKey = client.register(selector, SelectionKey.OP_READ);
            //判断是否是读
        } else if (selectionKey.isReadable()) {
            //获取客户端管道
            client = (SocketChannel) selectionKey.channel();
            //读取缓冲区
            count = client.read(receiveBuffer);
            if (count > 0) {
                //获取缓冲区的数据
                resiveMessage = new String(receiveBuffer.array(), 0, count);
                System.out.println("服务端读取客户端数据：" + resiveMessage);
                //注册selector 写
                selectionKey = client.register(selector, SelectionKey.OP_WRITE);
            }
        } else if (selectionKey.isWritable()) {
            //清空发送的缓冲区
            sendBuffer.clear();
            client = (SocketChannel) selectionKey.channel();
            //需要发送的数据
            sendMessage = "message send to client" + flag++;
            sendBuffer.put(sendMessage.getBytes());
            //写到缓冲区中
            sendBuffer.flip();
            //发送数据给缓冲区
            client.write(sendBuffer);
            System.out.println("服务端发送消息给客户端" + sendMessage);
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        int port = 8801;
        NIOServer nioServer = new NIOServer(port);
        nioServer.listen();

    }

}
